package com.piece.core.web.aspect;

import com.piece.core.framework.annotation.permission.AclPermission;
import com.piece.core.framework.constant.FrameWorkConstants;
import com.piece.core.framework.constant.PermissionConstants;
import com.piece.core.framework.exception.ErrorCode;
import com.piece.core.framework.exception.FrameWorkException;
import com.piece.core.framework.exception.PermissionException;
import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.util.basic.PermissionUtil;
import com.piece.core.framework.util.basic.SpringUtil;
import com.piece.core.framework.util.string.StringUtil;
import com.piece.core.log.client.dto.UserDTO;
import com.piece.core.log.config.UserContextHolder;
import com.piece.core.web.authority.AuthorityFactory;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.HandlerMapping;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 权限管理切面
 */
@Slf4j
@Aspect
@Order(1)
public class PermissionAspect {

    @Autowired
    private AuthorityFactory authorityFactory;

    @Before("@annotation(acl)")
    public void before(JoinPoint point, AclPermission acl) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        AclPermission aclPerm = method.getAnnotation(AclPermission.class);
        if (null != aclPerm) {
            try {
                boolean pass = false;
                String err_code = aclPerm.code();
                HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

                if (aclPerm.checkLogin()) {
                    UserDTO login = UserContextHolder.get();
                    if (null == login) {
                        throw new FrameWorkException(ErrorCode.PERMISSION);
                    }
                }

                if (StringUtil.isNotEmpty(aclPerm.code())) {
                    List<String> perms = Arrays.asList((aclPerm.code().split(FrameWorkConstants.SPLIT_PARAM)));

                    for (String perm : perms) {
                        if (authorityFactory.get().isPermitted(perm)) {
                            pass = true;
                            break;
                        }
                    }
                } else if (StringUtil.isNotEmpty(aclPerm.proxy())) {
                    String param = null;
                    if (StringUtil.isNotEmpty(aclPerm.param())) {
                        param = request.getParameter(aclPerm.param());
                        param = param == null ? aclPerm.param() : param;
                    }

                    String[] beanMethods = aclPerm.proxy().split("[.]");
                    String beanId = beanMethods[0];
                    String methodName = beanMethods[1];
                    Object serviceBean = SpringUtil.getBean(beanId);
                    Method invokeMethod = serviceBean.getClass().getDeclaredMethod(methodName, String.class);
                    pass = (Boolean) invokeMethod.invoke(serviceBean, param);
                } else if (aclPerm.checkOwner()) {
                    String param = null;
                    if ("path".equals(aclPerm.checkParamType())) {
                        Map map = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
                        param = Convert.toStr(map.get(aclPerm.checkParam()), null);
                    } else {
                        param = request.getParameter(aclPerm.checkParam());
                    }

                    if (StringUtil.isNotEmpty(param)) {
                        UserDTO login = UserContextHolder.get();
                        if (null == login || !login.getId().equals(param)) {
                            throw new FrameWorkException(ErrorCode.PERMISSION);
                        }
                        pass = true;
                    }

                    err_code = PermissionConstants.EDIT_PERMISSION;
                } else {
                    pass = true;
                }

                if (!pass) {
                    throw new PermissionException(PermissionUtil.getMsg(err_code));
                }
            } catch (Exception e) {
                log.info("权限验证异常：{}", e.getMessage());
            }
        }
    }
}
